home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / Minimal App7 ƒ / Call_Resource.c next >
C/C++ Source or Header  |  1996-06-14  |  39KB  |  1,269 lines

  1. /* Call_Resource.c: file to be added to any applications wishing to
  2. call the code resources that come with EnterAct.
  3. THIS IS A COPY of the other Call_Resource.c file on your source disk,
  4. adapted for Minimal App. */
  5.  
  6. /* Copyright © 1991, 1992, 1993 the Free Software Foundation, Inc.
  7.  *         This file is free software; you can redistribute or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 1, or any later version.
  10.  *         This file is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  * GNU General Public License for more details.
  14.  *         You should have received a copy of the GNU General Public License
  15.  * along with GAWK; see the file "COPYING hAWK". If not, write to
  16.  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  * Written for THINK C 4 on the Macintosh by Ken Earle (Dynabyte) Aug 1991.
  18.  */
  19.  
  20. /*
  21. REVISION May 96: who needs version flags in a prototype? There is just one
  22. format now for the CallResource() call. If you have been using CallResource()
  23. in your app, note the new prototype is
  24. void CallResource
  25.     (short        menuID,
  26.     short        item,
  27.     Boolean        concurrent,        // set FALSE if you don't support concurrent mode
  28.     char        *commandLineP    // -> complete command line or NULL
  29.     );
  30. Now your CallResource() will have the same arguments no matter which version
  31. you support. If you don't support concurrent operation (see below) then just
  32. set "concurrent" to FALSE. If you aren't passing in a command line, set
  33. commandLineP to NULL. If you want to support concurrent operation, you will
  34. still need to set VERSION2 TRUE as explained below. To pass a command line,
  35. put a pointer to a C string in commandLineP in the CallResource() call in
  36. your application (no changes needed here).
  37.  
  38. MinimalApp sets VERSION2 TRUE and supports concurrent mode, but does not
  39. pass a command line since it has at present no source for such a thing.
  40.  
  41. To call EnterAct-style code resources from your application:
  42. 1    Add a copy of this file to your app.
  43. 2    Call "InitCallResources()" in your startup code, just before
  44.     entering your event loop. The arguments are:
  45.     vRefNumForApp : preferably your application working directory, or 0
  46.     codeFolderName : preferably (Ptr)"\pDrag_on Modules"
  47.     menuID : the integer menu id of the menu you wish code resources
  48.         to be appended to. Preferably not File or Edit.
  49. 3    Call "CallResource()" to handle the code resources picked from
  50.     the menu you have added them to. Typically looks something like
  51.         #define    MenuInQuestion    261
  52.         void DoMenuInQuestionCommand(short item)
  53.             {
  54.             switch (item)
  55.                 {
  56.             case 1:
  57.                 DoItemOne();
  58.             break;
  59.             case 2:
  60.                 DoItemTwo();
  61.             break;
  62.             ...etc...
  63.             default:
  64.                 if (item > 0)
  65.                     CallResource(MenuInQuestion, item);
  66.                     --or if you set VERSION2 == TRUE,
  67.                     CallResource(MenuInQuestion, item, true/false);
  68.                     --
  69.             break;
  70.                 }
  71.             }
  72. 4    Go through the extension ("callback") functions defined at the
  73.     bottom of this file, and decide which ones you wish to support.
  74.     You will probably not be able to support "InDictionary()", and
  75.     "GetNextMultiFile()" requires that your application keep a list
  76.     of files for some purpose or other (typically searching), but if
  77.     your application supports text files you should be able to provide
  78.     support for the others. Note "GetScreenHeight" and "GetScreenWidth"
  79.     are done here, no modification needed. The code resources supplied
  80.     with EnterAct can still do useful things even if no extensions are
  81.     supplied.
  82.     
  83.     If you decide not to support a particular extension, you need only
  84.     set the corresponding pointer to NULL in the function SetUpCodeCommunication().
  85.     For example, if you don't support InDictionary_Ext, then put
  86.         gacc.InDictionary_Ext = NULL;
  87.     in SetUpCodeCommunication().
  88.     
  89.     For more about the "DoEventLoopOnce()" callback, see 6 below.
  90.     
  91. 5    "ShowResult" and "SelectResult" defined below are called by
  92.     "CallResource" in response to a request by a code resource to display
  93.     the text results of the code resource run. If your application supports
  94.     TEXT documents, you should modify these functions to provide your
  95.     equivalents for these abilities. Otherwise, leave them as-is.
  96.  
  97. 6    Version 2 of hAWK (the one you received with this file) supports
  98. concurrent execution. This means you fire up a hAWK program, go back
  99. to working in your application (or even switch to some other app)
  100. and hAWK notifies you when the program is done. There is a
  101. penalty in speed of the hAWK program, usually far outweighed by
  102. the benefit of being able to go back to work instantly rather than
  103. having to sit there watching the watch cursor. Your calling application
  104. should not be noticeably affected, except when the hAWK program
  105. is doing something massive such as a huge "sort" or a large "copy".
  106.  
  107. The "VERSION2" defined constant just below should be set to TRUE if
  108. you wish to support concurrent execution of hAWK programs, FALSE
  109. if you do not. That's all that VERSION2 affects. Read Resource cannot
  110. run concurrently, and is not affected by the value of VERSION2.
  111.  
  112. To support concurrent exec of hAWK programs, follow these steps:
  113.     1    define VERSION2 just below to be TRUE
  114.     2    In the menu where you call Drag_on Modules, use
  115.         ...CallResource(MenuInQuestion, item, bool);
  116.         rather than just CallResource(MenuInQuestion, item);
  117.         -the "bool" variable is a Boolean, to be set to TRUE if
  118.         you want concurrent execution. Recommended interface is
  119.         to set this variable FALSE if the user has held down
  120.         either the <Shift> or <Option> key or both, and set it
  121.         TRUE otherwise.
  122.     3    One additional callback function needs to be provided,
  123.         in "DoEventLoopOnce()" below. Your callback should
  124.         have the form
  125.             extern void HandleOneEvent(void);
  126.         and can be a copy of your main event loop function,
  127.         except that it should handle just one event and then
  128.         return, and startup initializations if any can
  129.         be skipped (creating a region to track the mouse,
  130.         for example). If you use a global event record, you
  131.         can use the same global in your "HandleOneEvent"
  132.         function, but keep in mind that when "CallResource()"
  133.         returns, your global event record will reflect the
  134.         last event processed during your Drag_on Module run,
  135.         rather than the original menu call -- check what your
  136.         main event loop does with the event after the orginal
  137.         call, and verify that nothing important will be confused
  138.         by having the nature of the event changed during the
  139.         Drag_on Modules run.
  140.         (Note your event handler does not need to do any special
  141.         checking for the <Command><period> that stops hAWK.)
  142.     4    If your calling app is in the background when hAWK
  143.         finishes a run, a notice will be installed by the
  144.         DoNotify() routine below, flashing an icon in the
  145.         menu bar etc until you return to the calling app.
  146.         In your MAIN event handler (not the handle-one-event)
  147.         you should place the following bit of code to properly
  148.         handle the notify when your app resumes:
  149.             --declaration at the top of its file;
  150.                 -- to handle concurrent Drag_on Modules --
  151.                 Boolean gNotifying;
  152.                 Boolean gHawkIsRunning;
  153.                 NMRec    gNotifyRec;
  154.             
  155.             -- and in your main event handler, for the case of
  156.             "kSuspendResumeMessage";
  157.                 if (gNotifying)
  158.                     {
  159.                     NMRemove(&gNotifyRec);
  160.                     if (gNotifyRec.nmIcon)
  161.                         ReleaseResource(gNotifyRec.nmIcon);
  162.                     gNotifying = FALSE;
  163.                     ShowResultsAfterNotify();
  164.                     }
  165.         You will also need the standard global that records
  166.         whether or not your application is in the background,
  167.             Boolean gInBackground;
  168.         This variable should be set in your handle-one-event
  169.         function, and if your spelling of this variable name
  170.         differs from "gInBackground", change it here as well.
  171.         This file requires access to "gInBackground" in order
  172.         to determine if a notice should be posted at the end
  173.         of a hAWK program run.
  174.     5    In both your main event handler and the one-event
  175.         handler, calculate the "sleep" parameter for your
  176.         WaitNextEvent() call roughly as
  177.             gHawkIsRunning ? 2UL : GetCaretTime()
  178.         --adjust to suit your taste.
  179.     6    If you want the small icon "hAWK!" to flash for
  180.         notifications, move it to your application from "hAWK"
  181.         itself (it's just stored there).
  182.     7    One little wrinkle: what happens if you Quit your
  183.         application while hAWK is running? The recommended
  184.         solution here is to ask your user to issue a
  185.         <Command><period> to halt hAWK before proceeding
  186.         with the Quit. If you just pull the rug out from
  187.         under hAWK, files will probably be left open.
  188.         Sketchily:
  189.             Boolean DoQuit (...
  190.             extern Boolean gHawkIsRunning;...
  191.             if (gHawkIsRunning)
  192.                 {
  193.                 FlexAlert(justOK, stopIcon, "Please terminate your hAWK program \
  194.         with <Command><period> before quitting.");
  195.                 return(FALSE);
  196.                 }...
  197.     
  198. */
  199.  
  200. #include <string.h>
  201.  
  202. #ifndef NULL
  203. #define NULL        ((void *) 0)
  204. #endif
  205.  
  206. /* Change this to TRUE if you support concurrent hAWK - see above, point 6. */
  207. #define VERSION2 TRUE
  208.  
  209. #if VERSION2 == TRUE
  210. extern Boolean gInBackground;
  211. extern Boolean gNotifying;
  212. extern Boolean gHawkIsRunning;
  213. extern NMRec    gNotifyRec;
  214. #endif
  215.  
  216. /* Canned options, if you want to get going in a hurry:
  217. SUPPORT_LEVEL should be set to one of the following four options:
  218. MINIMAL - no extensions, no showing of results after a code resource run.
  219.     Note this doesn't mean the code resource won't be creating a text file,
  220.     it just means your application won't be showing it.
  221. RESULTSONLY - no extensions, but ability to show results supplied by you.
  222.     This means you should provide the hooks in ShowResult() and
  223.     SelectResult() - nothing else to do.
  224. BASICTEXT - in addition to providing the hooks in ShowResult() and
  225.     SelectResult(), fill in the blanks in GetFrontText() to allow the
  226.     code resource access to your front text window during a run.
  227. CUSTOMSUPPORT - ie avoid the above canned options.
  228.  
  229. There is one special case: if you support the "GetAppClip" extension,
  230. you’ll need to set SUPPORT_LEVEL to CUSTOMSUPPORT, and also
  231. define VERSION2 TRUE (getclip was not supported by version 1). NOTE this will
  232. also activate the PutAppClip extension. You must put your own function calls
  233. into GetAppClip and PutAppClip to make them functional.
  234.  
  235. OR you can do what's done here, and hack around the support_level
  236. restriction if, like Minimal App7, your app provides only minimal
  237. support but you want to implement the "getclip()" function in hAWK.
  238. */
  239.  
  240.  
  241. #define MINIMAL            1
  242. #define RESULTSONLY        2
  243. #define BASICTEXT        3
  244. #define CUSTOMSUPPORT    4
  245.  
  246. /* Pick yer pleasure - from the above 4 options only, please. */
  247. #define SUPPORT_LEVEL MINIMAL
  248.  
  249. /* Struct passed to all code resources. Everything should be optional.
  250. "stdInFileName" is primarily for code resources that insist on having input
  251. from an existing file - hAWK, for example. "stdOutFileName", however, is
  252. handy for use by any code resource that creates text, as this file can be
  253. shown by the calling application */
  254. typedef struct AppCodeComm
  255.     {
  256.     // c strings except as noted
  257.     char        *stdInFileName,    // text from application to code resource
  258.                 *stdInFileNameP, // pascal version of above
  259.                 *stdOutFileName, // text from code resource to application
  260.                 *stdErrFileName, // error messages from code resource
  261.                 *callerName,     // the name of your application
  262.                 *thisCodeName;     // name of code resource being called
  263.     short            result;
  264.     short            version; // currently 1 or 2
  265. // Extension ("callback") functions - ALL OPTIONAL. These pointers-to-functions
  266. // are all set in  SetUpCodeCommunication() just before calling a code resource.
  267.     short            (*InDictionary_Ext)(char *tokenName);
  268.     Handle        (*GetFrontText_Ext)(Boolean getItAll);
  269.     void        (*GetNextMultiFile_Ext)(short *panePtr, short *indexPtr, 
  270.                 short *vRefNumPtr, char *fileName, Boolean clearFlag);
  271.     short         (*OKStopAlert_Ext)(Ptr cstringPtr);
  272.     void        (*MemoryAlert_Ext)(void);
  273.     short            (*GetScreenHeight_Ext)(void);
  274.     short            (*GetScreenWidth_Ext)(void);
  275.     void        (*ShowWatchCursor_Ext)(void);
  276. // Concurrent exec, added for version 2
  277.     void        (*DoEventLoopOnce_Ext)(void);
  278. // Access to scrap/clip of calling app
  279.     Handle        (*GetAppClip_Ext)(void);
  280. // Added for version 3
  281.     long        extendID; // Caller should set to 'VER3'
  282.     short        (*PutAppClip_Ext)(char *newClipStr);
  283. // End of callback functions.
  284. // Added for version 4
  285.     long        extend2ID; // Caller should set to 'VER4'
  286.     char        *commandLine;
  287.     } AppCodeComm, *ACCPtr;
  288.  
  289. static AppCodeComm    gacc;
  290.  
  291. /* Your application name goes here. */
  292. static char callerName[] = "MinimalApp7";
  293.  
  294. typedef void (*CallCode)(ACCPtr ac);
  295.  
  296. static char *stdPathP;
  297.  
  298. typedef struct SpecificFolder
  299.     {
  300.     char     volName[32];
  301.     long    theDirID;
  302.     short        vRefNum;
  303.     } SpecificFolder;
  304. static SpecificFolder codeFolder;
  305.  
  306. /* Functions defined in this file: */
  307. /* Call this one towards the end of your startup, just before event loop */
  308. void InitCallResources(short vRefNumForApp, char *codeFolderName, short menuID);
  309. /* Called by InitCallResource: */
  310. void SetUpStandardFileNames(short vRefNum);
  311. void ShowResourcesInMenu(short vRefNumForApp, 
  312.     char *codeFolderName, short menuID);
  313. /* Two support routines for above */
  314. long FindCodeResFolder(short vRefNumForApp, char *codeFolderName);
  315. void AddCodesToMenu(long theDirID, short menuID);
  316. void OpenWDForCODE(void);
  317. /* Call this one in the "default" part of the switch for the
  318. menu containing the code resource names */
  319. void CallResource
  320.     (short        menuID,
  321.     short        item,
  322.     Boolean        concurrent,        // set FALSE if you don't support concurrent mode
  323.     char        *commandLineP    // -> complete command line or NULL
  324.     );
  325. #if VERSION2 == TRUE
  326. /* Enable/disable Drag_ons if running concurrently */
  327. void XableDrag_ons(short menuID, Boolean enable);
  328. /* Post a notify - NOTE this must be cleared by calling app */
  329. void DoNotify(void);
  330. /* For delayed showing of results */
  331. void ShowResultsAfterNotify(void);
  332. /* Beep and flush events */
  333. void AnnounceCompletion(void);
  334. #endif
  335.  
  336. /* Called by CallResource(), decide which extension functions to pass along */
  337. Boolean SetUpCodeCommunication(char *progName, char *commandLineP);
  338. /* Called by CallResource() to display results of resource run */
  339. Boolean ShowResult(char *name); /* either stdout or stderr */
  340. void SelectResult(void);
  341. /* A few support functions: */
  342. /* Pascal strings */
  343. void CopyPStr(Byte *srcStr, Byte *dstStr);
  344. void AppendPStr(Byte *s1, Byte *s2);
  345. Boolean PasEqualStrs(char *aStr, char *bStr);
  346. /* Files, names and locations */
  347. Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s);
  348. Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s);
  349. short    OpenWorkingDirectoryFromFullName(char *name, short len);
  350.  
  351. /* The extension functions - wrappers for your own calls */
  352. short InDictionary(char *tokenName);
  353. Handle GetFrontText(Boolean getItAll);
  354. void GetNextMultiFile(short *panePtr, short *indexPtr, 
  355.             short *vRefNumPtr, char *fileName, Boolean clearFlag);
  356. short OKStopAlert(Ptr cstringPtr);
  357. void MemoryAlert(void);
  358. short GetScreenHeight(void);
  359. short GetScreenWidth(void);
  360. void ShowWatchCursor(void);
  361. void DoEventLoopOnce(void);
  362. Handle GetAppClip(void);
  363. short PutAppClip(char *newClipStr);
  364.  
  365.  
  366.  
  367.  
  368. /* Call just before entering your event loop.
  369. Sets up full path names for standard in/out/err files,
  370. adds any code resources present to the menu of your choice.
  371. */
  372. void InitCallResources(short vRefNumForApp, char *codeFolderName, short menuID)
  373.     {
  374.     SetUpStandardFileNames(vRefNumForApp);
  375.     ShowResourcesInMenu(vRefNumForApp, codeFolderName, menuID);
  376.     }
  377.  
  378. /* Called once at beginning of application. Sets up full path names
  379. for std in/out/err files, and as a bonus sets gacc.callerName.
  380. The vRefNum passed in should be the application's vRefNum, but
  381. can be any old thing you want.
  382. -you can determine your application vrefnum at startup with
  383. short        appVRefNum;
  384. if (GetVol(NULL, &appVRefNum))
  385.     appVRefNum = 0;
  386.  */
  387. void SetUpStandardFileNames(short vRefNum)
  388.     {
  389.     if (!vRefNum)
  390.         GetVol(NULL, &vRefNum);
  391.     stdPathP = NewPtr(256);
  392.     if (MemError() != noErr)
  393.         goto PathTrouble;
  394.     gacc.stdInFileName = NewPtr(256);
  395.     if (MemError() != noErr)
  396.         goto PathTrouble;
  397.     gacc.stdInFileNameP = NewPtr(256);
  398.     if (MemError() != noErr)
  399.         goto PathTrouble;
  400.     gacc.stdOutFileName = NewPtr(256);
  401.     if (MemError() != noErr)
  402.         goto PathTrouble;
  403.     gacc.stdErrFileName = NewPtr(256);
  404.     if (MemError() != noErr)
  405.         goto PathTrouble;
  406.     if (vRefNum)
  407.         (void)(FullPathNameFromVRefNum(vRefNum, (Byte *)stdPathP));
  408.     else
  409.         stdPathP[0] = 0;
  410.     PtoCstr((StringPtr)stdPathP);
  411.     strcpy((Ptr)(gacc.stdInFileName), (Ptr)stdPathP);
  412.     strcpy((Ptr)(gacc.stdInFileNameP), (Ptr)stdPathP);
  413.     strcpy((Ptr)(gacc.stdOutFileName), (Ptr)stdPathP);
  414.     strcpy((Ptr)(gacc.stdErrFileName), (Ptr)stdPathP);
  415.     strcat((Ptr)(gacc.stdInFileName), "$tempStdIn");
  416.     strcat((Ptr)(gacc.stdInFileNameP), "$tempStdIn");
  417.     strcat((Ptr)(gacc.stdOutFileName), "$tempStdOut");
  418.     strcat((Ptr)gacc.stdErrFileName, "$tempStdErr");
  419.     CtoPstr((Ptr)(gacc.stdInFileNameP));
  420.     gacc.callerName = NewPtr(strlen(callerName)+1);
  421.     if (MemError() != noErr)
  422.         goto PathTrouble;
  423.     strcpy(gacc.callerName, callerName);
  424.     
  425.     return;
  426. PathTrouble:
  427.     OKStopAlert("Out of memory right at the start! \
  428. Blew the tubes trying to allocate standard file names.");
  429.     ExitToShell();
  430.     }
  431.  
  432. /* Index through folders in application's folder, looking for
  433. "\pDrag_on Modules". If found, index through files in folder and add
  434. any resource files found. */
  435. void ShowResourcesInMenu(short vRefNumForApp, 
  436.     char *codeFolderName, short menuID)
  437.     {
  438.     long    theDirID;
  439.     
  440.     if (theDirID = FindCodeResFolder(vRefNumForApp, codeFolderName))
  441.         AddCodesToMenu(theDirID, menuID);
  442.     }
  443.  
  444. long FindCodeResFolder(short vRefNumForApp, char *codeFolderName)
  445.     {
  446.     HFileInfo    myCPB;
  447.     WDPBRec        theParms;
  448.     char        fName[32];
  449.     long        theDirID;
  450.     short            index = 1, len;
  451.     OSErr        err;
  452.     
  453.     /* First extract "\pVolName:", volRef, and dirID for application folder */
  454.     theParms.ioNamePtr = (StringPtr)(codeFolder.volName);
  455.     theParms.ioVRefNum = vRefNumForApp;
  456.     theParms.ioWDIndex = 0;
  457.     theParms.ioWDProcID = 0;
  458.     theParms.ioWDVRefNum = 0;
  459.     if (PBGetWDInfo(&theParms,false))
  460.         return(0L);
  461.     len = codeFolder.volName[0];
  462.     codeFolder.volName[len + 1] = ':';
  463.     codeFolder.volName[0] = len + 1;
  464.     codeFolder.vRefNum = theParms.ioWDVRefNum;
  465.     theDirID = theParms.ioWDDirID;
  466.     
  467.     myCPB.ioNamePtr = (StringPtr)fName;
  468.     myCPB.ioVRefNum = vRefNumForApp;
  469.     do
  470.         {
  471.         myCPB.ioFDirIndex = index;
  472.         myCPB.ioDirID = theDirID;
  473.         if ((err = PBGetCatInfo((CInfoPBPtr)&myCPB, FALSE)) == noErr)
  474.             {
  475.             if (((myCPB.ioFlAttrib>>4) & 0x01) == 1) /* a folder */
  476.                 {
  477.                 if (PasEqualStrs(fName, codeFolderName))
  478.                     return(myCPB.ioDirID);
  479.                 }
  480.             }
  481.         ++index;
  482.         } while (err == noErr);
  483.     return(0L);
  484.     }
  485.  
  486. /* Search thru folder for code resources and add all codes to the menu. */
  487. void AddCodesToMenu(long theDirID, short menuID)
  488.     {
  489.     HFileParam     fp;
  490.     MenuHandle     theMenu;
  491.     char        fName[32];
  492.     short            index = 1;
  493.     OSErr        err;
  494.     Boolean        firstAdd = TRUE;
  495.     
  496.     theMenu = GetMHandle(menuID);
  497.     codeFolder.theDirID = theDirID;
  498.     fp.ioNamePtr = (StringPtr)fName;;
  499.     fp.ioVRefNum = codeFolder.vRefNum;
  500.     fp.ioFVersNum = 0;
  501.     do
  502.         {
  503.         fp.ioFDirIndex = index;
  504.         fp.ioDirID = codeFolder.theDirID;
  505.         if ((err = PBHGetFInfoSync((HParmBlkPtr)&fp)) == noErr)
  506.             {
  507.             if (fp.ioFlFndrInfo.fdType == 'rsrc'
  508.                 && fp.ioFlFndrInfo.fdCreator == 'RSED')
  509.                 {
  510.                 if (firstAdd)
  511.                     {
  512.                     AppendMenu(theMenu, (StringPtr)"\p-");
  513.                     firstAdd = FALSE;
  514.                     }
  515.                 AppendMenu(theMenu, (StringPtr)fName);
  516.                 }
  517.             }
  518.         ++index;
  519.         } while (err == noErr);
  520.     /****** Open a working directory for the CODE folder: this is currently required
  521.     for hAWK, but will be eliminated for hAWK's next version. */
  522.     if (!firstAdd)
  523.         OpenWDForCODE();
  524.     }
  525.  
  526. /****** Open a working directory for the CODE folder: this is currently required
  527. for hAWK, but will be eliminated for hAWK's next version. */
  528. void OpenWDForCODE()
  529.     {
  530.     WDPBRec        theParms;
  531.     
  532.     theParms.ioCompletion = NULL;
  533.     theParms.ioVRefNum = codeFolder.vRefNum;
  534.     theParms.ioNamePtr = NULL;
  535.     theParms.ioWDDirID = codeFolder.theDirID;
  536.     theParms.ioWDProcID = 'ERIK';
  537.     if (!PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  538.         codeFolder.vRefNum = theParms.ioVRefNum;
  539.     }
  540.  
  541. /* The main event. Given a pick from your menu, load and call
  542. the resource. Display results if asked to by the resource.
  543. */
  544. void CallResource
  545.     (short        menuID,
  546.     short        item,
  547.     Boolean        concurrent,        // set FALSE if you don't support concurrent mode
  548.     char        *commandLineP    // -> complete command line or NULL
  549.     )
  550.     {
  551.     MenuHandle     theMenu;
  552.     Handle        rHdle;
  553.     CallCode    codeCaller;
  554.     char        codeNameString[64];
  555.     long        eof;
  556.     short        saveVol, refNum;
  557.     
  558.     theMenu = GetMHandle(menuID);
  559.     GetItem(theMenu, item, (StringPtr)codeNameString);
  560.     if (31 < (unsigned char)(codeNameString[0]))
  561.         {
  562.         /* An odd error: if the code resource was added to the menu during
  563.         startup, how can it have a name that is longer than a file name?
  564.         The assumption here is that we are calling something that is not a
  565.         code resource - either the wrong menu or an inappropriate item.
  566.         Uncomment the following alert if you want to double-check this.
  567.         
  568.         OKStopAlert("Code resource name is too long.");
  569.         */
  570.         return;
  571.         }
  572.     gacc.thisCodeName = NULL;
  573.     if (GetVol(NULL, &saveVol))
  574.         saveVol = 0;
  575.     SetVol(NULL, codeFolder.vRefNum);
  576.     /* See if there's enough memory to load the code resource
  577.     - the brute force approach, if anything more strict than necessary. */
  578.     if (HOpenRF(codeFolder.vRefNum, codeFolder.theDirID,
  579.                 (StringPtr)codeNameString, fsRdPerm, &refNum))
  580.         {
  581.         if (saveVol)
  582.             SetVol(NULL, saveVol);
  583.         OKStopAlert("Couldn't open the code resource.");
  584.         return;
  585.         }
  586.     if (GetEOF(refNum, &eof))
  587.         {
  588.         FSClose(refNum);
  589.         if (saveVol)
  590.             SetVol(NULL, saveVol);
  591.         OKStopAlert("Code resource seems damaged or empty - giving up.");
  592.         return;
  593.         }
  594.     FSClose(refNum);
  595.     rHdle = NewHandle(eof + eof/10); /* a guess */
  596.     if (MemError() != noErr)
  597.         {
  598.         if (saveVol)
  599.             SetVol(NULL, saveVol);
  600.         OKStopAlert("Not enough memory to proceed, sorry.");
  601.         return;
  602.         }
  603.     DisposHandle(rHdle);
  604.     rHdle = NULL;
  605.     if ((refNum = HOpenResFile(codeFolder.vRefNum, codeFolder.theDirID,
  606.                 (StringPtr)codeNameString, fsRdPerm)) != -1 && refNum
  607.                 && ResError() == noErr)
  608.         {
  609.         /* load CODE 0, set up extensions etc, lock down and call
  610.         -after, show results */
  611.         rHdle = Get1Resource ('CODE', 0);
  612.         if (!rHdle)
  613.             {
  614.             /* In error thinking it was a code resource - this really isn't fair */
  615.             CloseResFile(refNum);
  616.             if (saveVol)
  617.                 SetVol(NULL, saveVol);
  618.             OKStopAlert("CODE 0 from that resource file seems to be missing.");
  619.             return;
  620.             }
  621. #if VERSION2 == TRUE
  622.         gHawkIsRunning = TRUE;
  623.         XableDrag_ons(menuID, FALSE);
  624.         HiliteMenu(0);
  625. #endif
  626.         HLock(rHdle);
  627.         codeCaller = (CallCode)*rHdle;
  628.         SetUpCodeCommunication(codeNameString, commandLineP);
  629. #if VERSION2 == TRUE
  630.         if (!concurrent)
  631.             gacc.DoEventLoopOnce_Ext = NULL;
  632. #endif
  633.         codeCaller(&gacc);
  634.             
  635.         HUnlock(rHdle);
  636.         ReleaseResource(rHdle);
  637.         CloseResFile (refNum);
  638. #if VERSION2 == TRUE
  639.         XableDrag_ons(menuID, TRUE);
  640. #endif
  641.         }
  642.     else
  643.         OKStopAlert("Could not open the resource fork for that code resource.");
  644.     if (saveVol)
  645.         SetVol(NULL, saveVol);
  646.     /* Show any file requested */
  647.     /* results:
  648.     <= -3 : no action at present
  649.     -2 : show stderr
  650.     -1 : user cancelled or error during dialog - no run
  651.     0  : run OK, do nothing special after
  652.     1  : show stdout
  653.     2  : show and select stdout
  654.     > 2 : no action at present (counts as equivalent to 0)
  655.     */
  656.  
  657. #if VERSION2 == TRUE
  658.     if (!(gHawkIsRunning && gInBackground))
  659.         {
  660.         // Go quietly if run from command line.
  661.         if (commandLineP == NULL)
  662.             AnnounceCompletion();
  663.         }
  664.     if (gHawkIsRunning && gInBackground)
  665.         {
  666.         // Go quietly if run from command line.
  667.         if (commandLineP == NULL)
  668.             DoNotify();
  669.         }
  670.     else
  671. #endif
  672.  
  673.     if (gacc.result == -2)
  674.         ShowResult(gacc.stdErrFileName);
  675.     else if (gacc.result == 1 || gacc.result == 2)
  676.         {
  677.         if (ShowResult(gacc.stdOutFileName) && gacc.result == 2)
  678.             SelectResult();
  679.         }
  680.  
  681. #if VERSION2 == TRUE
  682.     gHawkIsRunning = FALSE;
  683. #endif
  684.  
  685.     /* A small cleanup after */
  686.     if (gacc.thisCodeName)
  687.         DisposPtr(gacc.thisCodeName);
  688.     }
  689.  
  690. #if VERSION2 == TRUE
  691. void XableDrag_ons(short menuID, Boolean enable)
  692.     {
  693.     MenuHandle menu = GetMHandle(menuID);
  694.     char    mText[64];
  695.     short        i;
  696.     
  697.     if (!menu) return;
  698.     i = CountMItems(menu);
  699.     GetItem(menu, i, (StringPtr)mText);
  700.     while (i >= 1 && mText[1] != '-')
  701.         {
  702.         if (enable)
  703.             EnableItem(menu, i);
  704.         else
  705.             DisableItem(menu, i);
  706.         --i;
  707.         GetItem(menu, i, (StringPtr)mText);
  708.         }
  709.     }
  710.  
  711. /* Post a notify. Beep, small icon, diamond beside calling app's name.
  712. NOTE when the calling app resumes, it should remove this notify and
  713. show results, with
  714.         if (gNotifying)
  715.             {
  716.             NMRemove(&gNotifyRec);
  717.             if (gNotifyRec.nmIcon)
  718.                 ReleaseResource(gNotifyRec.nmIcon);
  719.             gNotifying = FALSE;
  720.             ShowResultsAfterNotify();
  721.             }
  722. */
  723. void DoNotify()
  724.     {
  725.     OSErr nmError;
  726.     
  727.     if (!gInBackground) return;
  728.     gNotifyRec.qType = nmType;
  729.     gNotifyRec.nmMark = 1;
  730.     gNotifyRec.nmIcon = GetResource('SICN', 128); /* or NULL */
  731.     HNoPurge(gNotifyRec.nmIcon);
  732.     gNotifyRec.nmSound = (Handle)-1L;
  733.     gNotifyRec.nmStr = 0L;
  734.     gNotifyRec.nmResp = (NMProcPtr)0L;
  735.     gNotifyRec.nmRefCon = 0L;
  736.     
  737.     nmError = NMInstall(&gNotifyRec);
  738.     gNotifying = TRUE;
  739.     }
  740.  
  741. void ShowResultsAfterNotify()
  742.     {
  743.     ;/* not implemented for Minimal App */
  744.     }
  745.  
  746. /* Beep when Drag_on is done, delay a bit to allow user to
  747. react, flush events. */
  748. void AnnounceCompletion()
  749.     {
  750.     long    startTime, endTime;
  751.     
  752.     
  753.     SysBeep(2);
  754.     Delay(0L, &startTime);
  755.     endTime = startTime;
  756.     while (endTime - startTime < 50L)
  757.         Delay(0L, &endTime);
  758.     FlushEvents(62, 0); /* key/mouse */
  759.     }
  760.  
  761. #endif
  762.  
  763.  
  764. /* If you don't support some extensions, set the pointer for it to NULL here. */
  765. Boolean SetUpCodeCommunication(char *progName, char *commandLineP)
  766.     {
  767.     short    len;
  768. #if SUPPORT_LEVEL >= BASICTEXT
  769.     /* MyTextInFront(), which should return TRUE if one of your text
  770.     windows is in front or second from front (normally at the time of the call
  771.     the hAWK setup dialog will be the front window).
  772.     */
  773.     extern Boolean MyTextInFront(void);
  774. #if SUPPORT_LEVEL == CUSTOMSUPPORT
  775.     /* CanDoMultiFiles() should return TRUE if the user has selected
  776.     any files for multi-file operations, however you define that.
  777.     */
  778.     extern Boolean CanDoMultiFiles(void);
  779. #endif
  780. #endif
  781.     gacc.result = 0; /* clear before run - 0 means don't do anything after */
  782.     
  783. #if VERSION2 == TRUE
  784.     gacc.version = 2;
  785. #else
  786.     gacc.version = 1;
  787. #endif
  788.     
  789.     gacc.extendID = 0; // Set to 'VER3' if you support PutAppClip
  790.     /* Extensions, set up every run */
  791.     gacc.GetScreenHeight_Ext = GetScreenHeight;
  792.     gacc.GetScreenWidth_Ext = GetScreenWidth;
  793.  
  794. // Our suport level is minimal, with a couple of hacks below.
  795. #if SUPPORT_LEVEL >= MINIMAL && SUPPORT_LEVEL <= BASICTEXT
  796. #if SUPPORT_LEVEL == BASICTEXT
  797.     if (MyTextInFront())
  798.         gacc.GetFrontText_Ext = GetFrontText; /* MODIFY GetFrontText()! */
  799.     else
  800.         gacc.GetFrontText_Ext = NULL;
  801. #else
  802.         gacc.GetFrontText_Ext = NULL;
  803. #endif
  804.     gacc.InDictionary_Ext = NULL;
  805.     gacc.GetNextMultiFile_Ext = NULL;
  806.     gacc.OKStopAlert_Ext = NULL;
  807.     gacc.MemoryAlert_Ext = NULL;
  808.     gacc.ShowWatchCursor_Ext = NULL;
  809. #if VERSION2 == TRUE
  810.     gacc.DoEventLoopOnce_Ext = DoEventLoopOnce;
  811.     /******* hack, in the standard version of Call_Resource.c the next line
  812.     reads "gacc.GetAppClip_Ext = NULL;". */
  813.     gacc.GetAppClip_Ext = GetAppClip;
  814. #else
  815.     gacc.DoEventLoopOnce_Ext = NULL;
  816.     gacc.GetAppClip_Ext = NULL;
  817. #endif
  818.  
  819. // ignore, our support level is minimal, technically
  820. #else /* CUSTOMSUPPORT - check all extension functions below. */
  821.     gacc.InDictionary_Ext = InDictionary;
  822.     if (MyTextInFront())
  823.         gacc.GetFrontText_Ext = GetFrontText;
  824.     else
  825.         gacc.GetFrontText_Ext = NULL;
  826.     if (CanDoMultiFiles())
  827.         gacc.GetNextMultiFile_Ext = GetNextMultiFile;
  828.     else
  829.         gacc.GetNextMultiFile_Ext = NULL;
  830.     gacc.OKStopAlert_Ext = OKStopAlert;
  831.     gacc.MemoryAlert_Ext = MemoryAlert;
  832.     
  833.     gacc.ShowWatchCursor_Ext = ShowWatchCursor;
  834. #if VERSION2 == TRUE
  835.     gacc.DoEventLoopOnce_Ext = DoEventLoopOnce;
  836.     gacc.GetAppClip_Ext = GetAppClip;
  837.     gacc.extendID = 'VER3';
  838. #else
  839.     gacc.DoEventLoopOnce_Ext = NULL;
  840.     gacc.GetAppClip_Ext = NULL;
  841. #endif
  842. #endif
  843.     
  844.     // A bit of a hack, we now support putclip so set extendID to ver3
  845.     gacc.extendID = 'VER3';
  846.     gacc.PutAppClip_Ext = PutAppClip;
  847. #if 0
  848.     if (gacc.extendID == 'VER3')
  849.         gacc.PutAppClip_Ext = PutAppClip;
  850.     else
  851.         gacc.PutAppClip_Ext = NULL;
  852. #endif
  853.     
  854.     // Command line arg.
  855.     gacc.commandLine = commandLineP;
  856.     if (commandLineP != NULL)
  857.         {
  858.         gacc.extend2ID = 'VER4';
  859.         }
  860.     else
  861.         {
  862.         gacc.extend2ID = 0;
  863.         }
  864.     /* Set up code resource name for each call. */
  865.     len = progName[0];
  866.     gacc.thisCodeName = NewPtr(len+1);
  867.     if (MemError() != noErr)
  868.         return(FALSE); /* No big deal - but suggests code resource will
  869.                         run into trouble real quick if can't get 32 bytes
  870.                         now...*/
  871.     BlockMove(progName, gacc.thisCodeName, len);
  872.     gacc.thisCodeName[len] = '\0';
  873.     return(TRUE);
  874.     }
  875.  
  876. /* This function is called by CallResource() to display the TEXT result
  877. of a code resource run. If your application supports TEXT files, you will
  878. have a function that takes a file name and vRefNum as arguments, and displays
  879. the TEXT file in a window - that's the one to use.
  880.  
  881. A small but important complication: if the file is already being displayed
  882. in a window, your application should close it without asking to save
  883. changes, and then reread it from disk. Changes not saved, because these
  884. are temporary files needed for communication between the application and
  885. the code resource. */
  886. Boolean ShowResult(char *name)
  887.     {
  888. #if SUPPORT_LEVEL >= RESULTSONLY
  889.     short vrefnum;
  890.     char filename[32];
  891.     short len = strlen(name);
  892.     Ptr    endPtr = name + len, startPtr = endPtr;
  893.  
  894.     extern Boolean MyAppShowResult(short vRefNum, char *fileName);
  895.  
  896.  
  897.     while (startPtr >= name)
  898.         {
  899.         if (*startPtr == ':')
  900.             break;
  901.         --startPtr;
  902.         }
  903.     ++startPtr;
  904.     if (startPtr >= endPtr) return(FALSE);
  905.     filename[0] = endPtr - startPtr;
  906.     BlockMove(startPtr, filename+1, filename[0]);
  907.     
  908.     vrefnum = OpenWorkingDirectoryFromFullName(name, (short)(startPtr - name));
  909.     if (!vrefnum) return(FALSE);
  910.     return(MyAppShowResult(vrefnum, filename));
  911. #else
  912.     return(FALSE);
  913. #endif
  914.  
  915. /* For reference, the entire "MyAppShowResult" function for EnterAct is
  916.     if (wdPtr = IsFileOpen(fileName, vRefNum))
  917.         DoForcedCloseWindow(wdPtr);
  918.     return(DoOpenFile(text, FALSE, vRefNum, fileName));
  919. */
  920.  
  921.     }
  922.  
  923. /* This function should select all of the text in the front window, after
  924. checking that the front window is indeed a text window. */
  925. void SelectResult()
  926.     {
  927. #if SUPPORT_LEVEL >= RESULTSONLY
  928.     extern void MyAppSelectResult(void);
  929.     
  930.     MyAppSelectResult();
  931. #endif
  932.     }
  933.  
  934. /* Pascal strings */
  935.  
  936. /* Copy one pascal string to another */
  937. void CopyPStr(Byte *srcStr, Byte *dstStr)
  938.     {
  939.     long   srcLen = srcStr[0];
  940.  
  941.     BlockMove(srcStr, dstStr, srcLen + 1);
  942.     }
  943.  
  944. /* Append pascal s2 to pascal s1, avoiding overflow. */
  945. void AppendPStr(Byte *s1, Byte *s2)
  946.     {
  947.     short    s1Len = s1[0];
  948.     short    s2Len = s2[0];
  949.  
  950.     if (s1Len + s2Len > 255)
  951.         s2Len = 255 - s1Len;
  952.  
  953.     if (s2Len)
  954.         {
  955.         BlockMove (s2 + 1, s1 + s1Len + 1, s2Len);
  956.         s1Len += s2Len;
  957.         s1[0] = s1Len;
  958.         }
  959.     }
  960.  
  961. Boolean PasEqualStrs(char *aStr, char *bStr)
  962.     {
  963.     short i, lena = aStr[0], lenb = bStr[0];
  964.     
  965.     if (!lena || !lenb || lena != lenb)return(FALSE);
  966.     for (i = 1; i <= lena; ++i)
  967.         {
  968.         if (aStr[i] != bStr[i])
  969.             return(FALSE);
  970.         }
  971.     return(TRUE);
  972.     }
  973.  
  974. /* Files, names and locations */
  975.  
  976. /* NOTE the following two functions are based on examples supplied
  977. by Apple on one of their DTS disks - error checking has been added,
  978. and these versions are independent of the signed vs unsigned char
  979. controversy surrounding str255. Byte is defined in MacTypes.h
  980. for THINK C v4. */
  981.  
  982. /* Warning, these calls can fail! And why not? Everything else can... */
  983. /* Bug, these two are not for use by unix imitations such as A/UX. */
  984.  
  985. /* Construct "\pDisk:folder1:folder2:...folderN:" where folderN
  986. contains the file of interest. */
  987. Byte *FullPathNameFromDirectory(long DirID, short vRefNum, Byte *s)
  988.     {
  989.     CInfoPBRec    pb;
  990.     Byte        directoryName[256];
  991.  
  992.     s[0] = 0;
  993.     pb.dirInfo.ioNamePtr = (StringPtr)directoryName;
  994.     pb.dirInfo.ioDrParID = DirID;
  995.  
  996.     do 
  997.         {
  998.         pb.dirInfo.ioVRefNum = vRefNum;
  999.         pb.dirInfo.ioFDirIndex = -1;
  1000.         pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  1001.         if (PBGetCatInfo(&pb, FALSE))
  1002.             {
  1003.             break;
  1004.             }
  1005.         /* Append a colon  */
  1006.         AppendPStr(directoryName, (Byte *)"\p:");
  1007.         AppendPStr(directoryName, s);
  1008.         CopyPStr(directoryName, s);
  1009.         } while (pb.dirInfo.ioDrDirID != 2);
  1010.     return(s);
  1011.     }
  1012.  
  1013.  
  1014. Byte *FullPathNameFromVRefNum(short vRefNum, Byte *s)
  1015.     {
  1016.  
  1017.     WDPBRec    pb;
  1018.  
  1019.     pb.ioNamePtr = NULL;
  1020.     pb.ioVRefNum = vRefNum;
  1021.     pb.ioWDIndex = 0;
  1022.     pb.ioWDProcID = 0;
  1023.  
  1024.     if (PBGetWDInfo(&pb,false))
  1025.         {
  1026.         s[0] = 0;
  1027.         return(s);
  1028.         }
  1029.     return(FullPathNameFromDirectory(pb.ioWDDirID,pb.ioWDVRefNum,s));
  1030.     }
  1031.  
  1032. /* Determine working directory for file based on full path name. */
  1033. short    OpenWorkingDirectoryFromFullName(char *name, short len)
  1034.     {
  1035.     WDPBRec        theParms;
  1036.     OSErr     IOResult;
  1037.     char volname[256];
  1038.     
  1039.     volname[0] = len;
  1040.     BlockMove(name, volname+1, len);
  1041.     
  1042.     theParms.ioCompletion = NULL;
  1043.     theParms.ioVRefNum = 0;
  1044.     theParms.ioNamePtr = (StringPtr)volname;
  1045.     theParms.ioWDDirID = 0;
  1046.     theParms.ioWDProcID = 'ERIK';
  1047.     if (IOResult = PBOpenWD(&theParms, FALSE)) /* IM IV pg 158 */
  1048.         {
  1049.         OKStopAlert("Disk may not be on-line, \
  1050. or file may have been moved, deleted, or renamed.");
  1051.         theParms.ioVRefNum = 0;
  1052.         }
  1053.     return(theParms.ioVRefNum);
  1054.     }
  1055.  
  1056.  
  1057. /* The extension functions.*/
  1058.  
  1059. /* InDictionary() returns the general C type
  1060. of a word, according to the following table:
  1061. value    C type
  1062. 0        none - keyword, comment word, local variable, operator etc
  1063. 1        #define or macro name    eg    #define TAB '\t'
  1064. 2        variable name with more than function scope
  1065. 4        function or method name
  1066. 8        enum constant
  1067. 16        typedef name
  1068. 32        struct tag
  1069. 64        union tag
  1070. 128        enum tag
  1071.  
  1072. See hAWK cross-referencing programs for an example of usage. It's unlikely
  1073. that you will be able to provide an equivalent for this function, and
  1074. there’s no great loss if you don’t.
  1075.  */
  1076. short InDictionary(char *tokenName)
  1077.     {
  1078. #if SUPPORT_LEVEL == CUSTOMSUPPORT
  1079.     extern short InMyAppDictionary(char *s);
  1080.     
  1081.     return(InMyAppDictionary(tokenName));
  1082. #else
  1083.     return(0);
  1084. #endif
  1085.     }
  1086.  
  1087. /* This extension function should copy all or the selected part of the
  1088. text in the frontmost window to a Handle. If the front window is not a
  1089. text window, you should try the second-front window - if it isn't text
  1090. either, return NULL. Front OR second front, because a dialog window may be
  1091. the front window at the time - this is the case with hAWK, for example.
  1092. */
  1093. Handle GetFrontText(Boolean getItAll)
  1094.     {
  1095. #if SUPPORT_LEVEL >= BASICTEXT
  1096.     extern Handle MyAppGetFrontText(Boolean getItAll);
  1097.     
  1098.     return(MyAppGetFrontText(getItAll));
  1099. #else
  1100.     return(NULL);
  1101. #endif
  1102.     }
  1103.  
  1104. /* This function should retrieve file names and vRefNums from a one
  1105. or two-dimensional list of files. If *panePtr == -1, you are being asked
  1106. for the first file, otherwise the next file. When there are no more files,
  1107. set *indexPtr = -1. If you have a two-dimensional list, think of panePtr as
  1108. the column index and indexPtr as the row index. For a one-dimensional list,
  1109. use indexPtr to keep track of where you are - just remember to set panePtr to
  1110. something != -1 during the first call. Other than setting panePtr to something
  1111. besides -1 during the first call, and setting indexPtr to -1 when there are
  1112. no more files, you can use them for tracking which file comes next in any way
  1113. you want.
  1114. If you perhaps use full path names, see OpenWorkingDirectoryFromFullName()
  1115. above for hints on how to convert to filename/vRefNum.
  1116. clearFlag TRUE means clear the file from your list; FALSE means leave it in the
  1117. list. Normally FALSE is best - someone might want to reuse the list quite soon,
  1118. as in running two hAWK programs on the same list of files.
  1119. */
  1120. void GetNextMultiFile(short *panePtr, short *indexPtr, 
  1121.             short *vRefNumPtr, char *fileName, Boolean clearFlag)
  1122.     {
  1123. #if SUPPORT_LEVEL == CUSTOMSUPPORT
  1124.     extern void GetNextFileToSearch(short *panePtr, short *indexPtr, 
  1125.         short *vRefNumPtr, char *fileName, Boolean clearFlag);
  1126.     
  1127.     GetNextFileToSearch(panePtr, indexPtr, 
  1128.                 vRefNumPtr, fileName, clearFlag);
  1129. #else
  1130.     *indexPtr = -1;
  1131. #endif
  1132.     }
  1133.  
  1134. /* If you have an alert mechanism with just an OK button that accepts C
  1135. strings, insert it here. Return of 1 means alert was shown and user
  1136. clicked OK, return of 0 means the alert was not shown. If this happens,
  1137. it would be quite OK for your alert function to try to get more memory or
  1138. show an out-of memory alert before returning the 0 or 1. */
  1139. short OKStopAlert(Ptr cstringPtr)
  1140.     {
  1141. #if SUPPORT_LEVEL == CUSTOMSUPPORT
  1142. /* Left in from EnterAct as an example - EnterAct uses FlexAlert(),
  1143. essentially as published in MacTutor Jan '91. As a small refinement, it
  1144. will display an out-of-memory alert if it runs into trouble. FlexAlert
  1145. sizes the alert box to fit the text, and also formats the text nicely. */
  1146.     extern short FlexAlert(short buttonMode, short whichIcon, Ptr csPtr);
  1147. #define JUSTOK    0
  1148. #define STOPICON    0
  1149.     return(FlexAlert(JUSTOK, STOPICON, cstringPtr));
  1150. #else
  1151.     return(0);
  1152. #endif
  1153.     }
  1154.  
  1155. /* Advise the user that memory has run out during code resource execution.
  1156. You must have something for this kicking around in your application - a
  1157. text message is much more likeable than a beep if things fo worng. */
  1158. void MemoryAlert()
  1159.     {
  1160. #if SUPPORT_LEVEL == CUSTOMSUPPORT
  1161.     extern void DoMemoryAlert(short msgNum, long memLimit);
  1162.  
  1163. #define NONELEFT        4
  1164.  
  1165.     DoMemoryAlert(NONELEFT, 0L);
  1166. #else
  1167.     SysBeep(2);
  1168. #endif
  1169.     }
  1170.  
  1171. short GetScreenHeight(void)
  1172.     {
  1173.     return(qd.screenBits.bounds.bottom - qd.screenBits.bounds.top);
  1174.     }
  1175.  
  1176. short GetScreenWidth()
  1177.     {
  1178.     return(qd.screenBits.bounds.right - qd.screenBits.bounds.left);
  1179.     }
  1180.  
  1181. void ShowWatchCursor()
  1182.     {
  1183. #if SUPPORT_LEVEL == CUSTOMSUPPORT
  1184.     extern void MySetWatchCursor(void);
  1185.     
  1186.     MySetWatchCursor();
  1187. #endif
  1188.  
  1189.     /* this goes something like:
  1190.     CursHandle        Watch; -- ToolboxUtil.h  enum constant --
  1191.     Watch = GetCursor(watchCursor);
  1192.     if (Watch)
  1193.         SetCursor (*Watch);
  1194.     else
  1195.         InitCursor();
  1196.     */
  1197.     }
  1198.  
  1199. void DoEventLoopOnce()
  1200.     {
  1201. #if VERSION2 == TRUE
  1202.     extern void HandleOneEvent(void);
  1203.     
  1204.     HandleOneEvent();
  1205. #endif
  1206.     }
  1207.  
  1208. Handle GetAppClip()
  1209.     {
  1210. /******** hack, the innards of this function are normally within the
  1211. wrapper "#if SUPPORT_LEVEL == CUSTOMSUPPORT"..."#endif".
  1212. Further hack, since Minimal App7 does not have its own clip,
  1213. it "borrows" the system's desk scrap. */
  1214. #if VERSION2 == TRUE
  1215.     PScrapStuff     scrapStuff;
  1216.     long            offset, sizeH;
  1217.     static Handle    scrapH;
  1218.     static short    scrapCount;
  1219.     
  1220.     scrapStuff = InfoScrap();
  1221.     if (scrapStuff->scrapCount != scrapCount)
  1222.         {
  1223.         scrapCount = scrapStuff->scrapCount;
  1224.         if ((sizeH = GetScrap(NULL, 'TEXT', &offset)) > 0)
  1225.             {
  1226.             if (!scrapH)
  1227.                 scrapH = NewHandle(sizeH);
  1228.             else
  1229.                 SetHandleSize(scrapH, sizeH);
  1230.             if (MemError() != noErr)
  1231.                 {
  1232.                 if (scrapH)
  1233.                     {
  1234.                     DisposHandle(scrapH);
  1235.                     scrapH = NULL;
  1236.                     }
  1237.                 return NULL;
  1238.                 }
  1239.             SetHandleSize(scrapH, 0);
  1240.             GetScrap(scrapH, 'TEXT', &offset);
  1241.             }
  1242.         }
  1243.     return scrapH; /* Note it may be NULL or length 0. */
  1244. #endif
  1245.     return(NULL);
  1246.     }
  1247.  
  1248. /* Added after some trepidation, this function actually changes the system-wide
  1249. desk scrap. Use with caution.
  1250. */
  1251. short PutAppClip(char *newClipStr)
  1252.     {
  1253.     Ptr        s = newClipStr;
  1254.     long    len = 0L;
  1255.     
  1256.     while (*s++)
  1257.         ++len;
  1258.     if (len > 0)
  1259.         {
  1260.         ScrapStuff         *scrapStuff;
  1261.         ZeroScrap();
  1262.         PutScrap(len,'TEXT', newClipStr);
  1263.         scrapStuff = InfoScrap();
  1264.         ++(scrapStuff->scrapCount);
  1265.         return 1;
  1266.         }
  1267.     return 0;
  1268.     }
  1269.